#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "ohos_types.h"
#include "cmsis_os2.h"
#include "iot_errno.h"
#include "iot_gpio.h"
#include "iot_gpio_ex.h"
#include "hi_spi.h"

#define IOT_SPI 0
#define OLED_RST 13
#define OLED_DC 14

typedef enum
{
    COMMAND = 0,
    DATA
} DATA_TYPE;

uint32_t oled_write(DATA_TYPE type, uint8_t data)
{
    IoTGpioSetOutputVal(OLED_DC, type);
    return hi_spi_host_write(IOT_SPI, &data, sizeof(data));
}

uint32_t oled_init(void)
{
    uint8_t cmds[] = {0xAE, 0xDA, 0x12, 0xD5, 0x80, 0xD9, 0xF1, 0xDB, 0x20, 0x81, 0xFF, 0xD3, 0x00, 0x40, 0x20, 0x00, 0xA1, 0xC8, 0xA4, 0xA6, 0x8D, 0x14, 0xAF};
    IoTGpioSetOutputVal(OLED_RST, 1);
    usleep(100000);
    IoTGpioSetOutputVal(OLED_RST, 0);
    usleep(100000);
    IoTGpioSetOutputVal(OLED_RST, 1);
    usleep(100000);
    for (size_t i = 0; i < sizeof(cmds) / sizeof(cmds[0]); i++)
    {
        uint32_t status = oled_write(COMMAND, cmds[i]);
        if (status != IOT_SUCCESS)
        {
            return status;
        }
    }
}

void oled_set_pos(uint8_t x, uint8_t y)
{
    oled_write(COMMAND, 0xb0 | y);
    oled_write(COMMAND, 0x10 | ((x & 0xf0) >> 4));
    oled_write(COMMAND, x & 0x0f);
}

void oled_fill(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint8_t data)
{
    for (uint8_t i = 0; i < height; i++)
    {
        oled_set_pos(x, y + i);
        for (uint8_t j = 0; j < width; j++)
        {
            oled_write(DATA, data);
        }
    }
}

static void SPITask(void)
{
    uint8_t ret;
    hi_spi_cfg_init_param init_param = { .is_slave = false };
    hi_spi_cfg_basic_info param =
    {
        .cpol = HI_SPI_CFG_CLOCK_CPOL_0,
        .cpha = HI_SPI_CFG_CLOCK_CPHA_0,
        .fram_mode = HI_SPI_CFG_FRAM_MODE_MOTOROLA,
        .data_width = HI_SPI_CFG_DATA_WIDTH_E_8BIT,
        .endian = HI_SPI_CFG_ENDIAN_LITTLE,
        .freq = 8000000,
    };
    // 初始化 GPIO13 作为 OLED RST
    IoTGpioInit(OLED_RST);
    IoTGpioSetFunc(OLED_RST, IOT_GPIO_FUNC_GPIO_13_GPIO);
    IoTGpioSetDir(OLED_RST, IOT_GPIO_DIR_OUT);
    // 初始化 GPIO14 作为 OLED DC
    IoTGpioInit(OLED_DC);
    IoTGpioSetFunc(OLED_DC, IOT_GPIO_FUNC_GPIO_14_GPIO);
    IoTGpioSetDir(OLED_DC, IOT_GPIO_DIR_OUT);
    // GPIO9 复用为 SPI0 TXD
    IoTGpioInit(9);
    IoTGpioSetFunc(9, IOT_GPIO_FUNC_GPIO_9_SPI0_TXD);
    // GPIO10 复用为 SPI0 CLK
    IoTGpioInit(10);
    IoTGpioSetFunc(10, IOT_GPIO_FUNC_GPIO_10_SPI0_CK);
    // GPIO11 复用为 SPI0 RXD
    IoTGpioInit(11);
    IoTGpioSetFunc(11, IOT_GPIO_FUNC_GPIO_11_SPI0_RXD);
    // GPIO12 复用为 SPI0 CS
    IoTGpioInit(12);
    IoTGpioSetFunc(12, IOT_GPIO_FUNC_GPIO_12_SPI0_CSN);
    // 初始化 SPI0，参数如上方结构体所示
    ret = hi_spi_init(IOT_SPI, init_param, &param);
    if (ret != IOT_SUCCESS)
    {
        printf("Failed to init SPI! Error: %d\n", ret);
        return;
    }
    // 初始化 OLED 屏幕
    ret = oled_init();
    if (ret != IOT_SUCCESS)
    {
        printf("Failed to init OLED! Error: %d\n", ret);
        return;
    }
    // 清屏并绘制矩形
    oled_fill(0, 0, 128, 8, 0x00);
    oled_fill(20, 2, 60, 3, 0xff);
    while (1)
    {
        sleep(1);
    }
}

void SPIExample(void)
{
    osThreadAttr_t attr;
    attr.name = "SPITask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 2048;
    attr.priority = osPriorityNormal;
    if (osThreadNew((osThreadFunc_t) SPITask, NULL, &attr) == NULL)
    {
        printf("Failed to create SPITask!\n");
    }
}

SYS_RUN(SPIExample);
